﻿using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using MimeKit;
using MimeKit.Text;
using MKAdminCore.DTO.Web.Common;
using MKAdminCore.DTO.Web.Login;
using MKAdminCore.IService.Web.Login;
using MKAdminCore.ToolKit.Config;
using MKAdminCore.ToolKit.EmailHelper;
using MKAdminCore.ToolKit.Encrypt;
using MKAdminCore.ToolKit.IpHelper;
using MKAdminCore.ToolKit.VerifyCodeHelper;
using Newtonsoft.Json;

namespace MKAdminCore.Controllers
{
    public class LoginController : Controller
    {
        private ILoginService _iLoginService;
        private readonly IHttpContextAccessor httpContextAccessor;
        private IMemoryCache _cache;

        public LoginController(ILoginService iLoginService, IHttpContextAccessor httpContextAccessor, IMemoryCache memoryCache)
        {
            _iLoginService = iLoginService;
            _cache = memoryCache;
            this.httpContextAccessor = httpContextAccessor;
        }

        [HttpGet]
        public IActionResult Index()
        {
            LoginInfoParameter model = new LoginInfoParameter();
            var claimsQuery = HttpContext.User.Claims;
            var claimsInfo = claimsQuery.Where(q => q.Type == "UserInfo").FirstOrDefault();

            if (claimsInfo != null && !string.IsNullOrEmpty(claimsInfo.Value))
            {
                var userInfo = Newtonsoft.Json.JsonConvert.DeserializeObject<UserInfo>(claimsInfo.Value);
                //自动登录到主页
                return View(PageViewFilesConfig.Home, userInfo);
            }

            //获取cookie
            string cookieInfo = string.Empty;
            bool loginCookieStatus = HttpContext.Request.Cookies.TryGetValue("MKAdmin_LoginInfo", out cookieInfo);
            if (loginCookieStatus)
            {
                //反序列化
                var loginCookieInfo = JsonConvert.DeserializeObject<LoginCookieInfo>(cookieInfo);
                if (loginCookieInfo != null && !string.IsNullOrEmpty(loginCookieInfo.OperatorNo))
                {
                    model.OperatorNo = loginCookieInfo.OperatorNo;
                    model.OperatorPwd = loginCookieInfo.OperatorPwd;
                    model.IsRemember = true;
                }
            }
            return View(PageViewFilesConfig.Login, model);
        }

        [HttpPost]
        [ValidateAntiForgeryToken()]
        public async Task<IActionResult> Index(LoginInfoParameter parameter)
        {
            if (!string.IsNullOrEmpty(parameter.OperatorNo))
            {
                parameter.OperatorNo = parameter.OperatorNo.Trim();
                if (!string.IsNullOrEmpty(parameter.OperatorPwd))
                {
                    var ipAddress = httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();

                    if (string.IsNullOrEmpty(parameter.YzmCode))
                    {
                        ModelState.AddModelError(parameter.KeyValidateMessage, "请输入验证码");
                        return View("~/Views/Login/Index.cshtml", parameter);
                    }
                    //验证验证码
                    var yzmCodeValue = _cache.Get(parameter.YzmToken).ToString();
                    //var yzmCodeValue = RedisStringHelper.Get(parameter.YzmToken);
                    if (string.IsNullOrEmpty(yzmCodeValue) ||
                        string.IsNullOrEmpty(parameter.YzmCode) ||
                        yzmCodeValue.ToLower() != parameter.YzmCode.ToLower())
                    {
                        ModelState.AddModelError(parameter.KeyValidateMessage, "验证码输入错误");
                        return View("~/Views/Login/Index.cshtml", parameter);
                    }

                    var loginInfo = _iLoginService.UserLogin(parameter);
                    //记录登录日志
                    await _iLoginService.UserLoginLog(parameter.OperatorNo, loginInfo.status, ipAddress);
                    if (loginInfo.status)
                    {
                        //有用户登录 邮件通知
                        //配置的邮箱地址和密码才邮件通知
                        //var mailBoxAddress = new List<MailboxAddress>();
                        //mailBoxAddress.Add(new MailboxAddress("mikeit@163.com"));
                        //await EmailHelper.SendEMailAsync($"用户 {parameter.OperatorNo} 登录成功"
                        //    , $"登录成功,账号:{parameter.OperatorNo},IP:{ipAddress}", mailBoxAddress, TextFormat.Html);

                        var info = new UserInfo();
                        info.OperatorId = loginInfo.data.OperatorId;
                        info.OperatorNo = loginInfo.data.OperatorNo;
                        info.OperatorName = loginInfo.data.OperatorName;

                        var claims = new[] { new Claim("UserInfo", JsonConvert.SerializeObject(info)) };

                        var claimsIdentity = new ClaimsIdentity(
                        claims,
                        CookieAuthenticationDefaults.AuthenticationScheme);

                        ClaimsPrincipal user = new ClaimsPrincipal(claimsIdentity);

                        Task.Run(async () =>
                        {
                            //登录用户，相当于ASP.NET中的FormsAuthentication.SetAuthCookie
                            //定义了用户登录后60分钟内cookie都会保留在客户端计算机硬盘上

                            //即便用户关闭了浏览器，60分钟内再次访问站点仍然是处于登录状态，除非调用Logout方法注销登录。
                            //注意其中的AllowRefresh属性，如果AllowRefresh为true，表示如果用户登录后在超过50%的ExpiresUtc时间间隔内又访问了站点，就延长用户的登录时间（其实就是延长cookie在客户端计算机硬盘上的保留时间），
                            //例如本例中我们下面设置了ExpiresUtc属性为60分钟后，那么当用户登录后在大于30分钟且小于60分钟内访问了站点，那么就将用户登录状态再延长到当前时间后的60分钟。但是用户在登录后的30分钟内访问站点是不会延长登录时间的，
                            //因为ASP.NET Core有个硬性要求，是用户在超过50%的ExpiresUtc时间间隔内又访问了站点，才延长用户的登录时间。
                            //如果AllowRefresh为false，表示用户登录后60分钟内不管有没有访问站点，只要60分钟到了，立马就处于非登录状态（不延长cookie在客户端计算机硬盘上的保留时间，60分钟到了客户端计算机就自动删除cookie）

                            await HttpContext.SignInAsync(
                            CookieAuthenticationDefaults.AuthenticationScheme,
                            user, new AuthenticationProperties()
                            {
                                IsPersistent = true,
                                ExpiresUtc = DateTimeOffset.UtcNow.AddHours(16),
                                AllowRefresh = true
                            });

                        }).Wait();

                        //登录成功,如果需要记住账号密码,则需要保存cookie
                        if (parameter.IsRemember)
                        {
                            var cookieInfo = new LoginCookieInfo()
                            {
                                OperatorNo = parameter.OperatorNo,
                                OperatorPwd = parameter.OperatorPwd
                            };
                            HttpContext.Response.Cookies.Append("MKAdmin_LoginInfo"
                                , JsonConvert.SerializeObject(cookieInfo)
                                , new CookieOptions()
                                {
                                    Expires = new DateTimeOffset(DateTime.Now.AddDays(7))
                                });
                        }
                        else
                        {
                            HttpContext.Response.Cookies.Delete("MKAdmin_LoginInfo");
                        }

                        return Redirect("/");
                    }
                    else
                    {
                        ModelState.AddModelError(parameter.KeyValidateMessage, "登录名或密码错误");
                    }
                }
                else
                {
                    ModelState.AddModelError(parameter.KeyValidateMessage, "请输入密码");
                }
            }
            else
            {
                ModelState.AddModelError(parameter.KeyValidateMessage, "请输入登录名");
            }

            return View("~/Views/Login/Index.cshtml", parameter);
        }

        [HttpPost]
        public IActionResult GetVerifyCode()
        {
            string code = VerifyCodeHelper.GetSingleObj().CreateVerifyCode(VerifyCodeHelper.VerifyCodeType.MixVerifyCode);

            var codeToken = "yzm_" + Guid.NewGuid().ToString("N");
            var bitmap = VerifyCodeHelper.GetSingleObj().CreateBitmapByImgVerifyCode(code, 100, 40);
            MemoryStream stream = new MemoryStream();

            bitmap.Save(stream, ImageFormat.Jpeg);

            string imgCode = Convert.ToBase64String(stream.ToArray());

            _cache.Set(codeToken, code, new TimeSpan(0, 10, 0));
            //RedisStringHelper.Set(codeToken, code, new TimeSpan(0, 10, 0));

            var codeInfo = new
            {
                token = codeToken,
                imgCode = imgCode
            };

            return Ok(codeInfo);
        }
    }
}